﻿using System;
using System.Text;
using System.Collections;
using System.Web.UI.WebControls;
using System.Reflection;
using System.IO;
using System.Xml;
using Grishko.DataTier;
using Grishko.SerilizeTools;

namespace Ecopsy.Tools
{

    /// <summary>
    /// Суть. 
    /// Инкапсулировать where выражение LINQ запроса  в объект с возможностью сохранить в БД.
    /// Объект содержит Match - хранилище объекта с которым производиться сравнение 
    /// SortCondition - ханилище для инф. о сортировке - направление поля и т.п.
    /// SortCondition ,Match - совершенно произвольные хранилища - как будет обрабатываться информация - решается в методе Compare
    /// объекта Comparer
    /// В базовом варианте   есть WhereComparer - который принимает делегат - занимающийся Compare.
    /// </summary>
    public class WhereCondition : EntitySingle
    {
        public delegate int fWhereConditionCompare(object x, object y);

        /// <summary>
        /// Хранилище для условия where  
        /// </summary>
        public XmlWhere  Match { get; set; }
        
        private TSortCondition _SortCondition = new TSortCondition();
        public TSortCondition SortCondition { get { return _SortCondition; } set { _SortCondition = value; } }


        public Func<object, object, int> fWhere { get; set; }

        public int Compare(object x)
        {
            return fWhere(x, Match);
        }

        /// <summary>
        /// класс контейнер для условий сортирвки
        /// </summary>
        public class TSortCondition : EntitySingle, IComparer
        {
            public SortDirection SortDirection { get; set; }
            public string SortField { get; set; }

            #region IComparer Members

            public Func<TSortCondition, object, object, int> fnOrderBy { get; set; }
            public int Compare(object x, object y)
            {
                return fnOrderBy(this, x, y); ;

            }

            #endregion
        }

        /// <summary>
        /// часто используемые алгоритмы сортировки - универсальныые для полей и объектов
        /// </summary>
        public static class SortFunctions
        {
            /// <summary>
            /// Фнкция сортирующая объекты по полю азаданному в SortCond.SortField 
            /// </summary>
            public static Func<WhereCondition.TSortCondition, object, object, int> fOrderBy = delegate(WhereCondition.TSortCondition SortCond, object x, object y)
            {
                // еси ссылка на один объект - объекты равны
                if (x == y) return 0;

                object vx = GetFieldValue(x, SortCond.SortField);
                object vy = GetFieldValue(y, SortCond.SortField);

                if (null == vx) return -1;
                if (null == vy) return 1;

                int r = vx.ToString().ToUpper().CompareTo(vy.ToString().ToUpper());

                if (0 == r) return r;

                if (SortCond.SortDirection == SortDirection.Ascending) return r;
                return (r > 0 ? -1 : 1);

            };

            private static object GetFieldValue(object Context, string FieldName)
            {
                try
                {
                    Type t = Context.GetType();
                    PropertyInfo p = t.GetProperty(FieldName);
                    return p.GetValue(Context, null); ;
                }
                catch
                {
                    return null;
                }
            }


        }
    }

    /// <summary>
    /// Xml параметр хранимой процедуры содержащий условия отбора списка объектов 
    /// </summary>
    public class XmlWhere : EntitySingle
    {
        // используемые при построениии XML
        protected const string tgWhereCondition = "WhereCondition";
        protected const string tgParamValueItem = "ParamValueItem";
        protected const string attID = "ID";
        protected const string tgPageSize = "PageSize";
        protected const string attStartRowIndex = "StartRowIndex";
        protected const string attEndRowIndex = "EndRowIndex";


        protected int _StartRowIndex = 0;
        protected int _EndRowIndex = 10000;

        ///<summary>
        /// Множество значений с которым будет сравниваться множество значений экземпляра 
        ///</summary>
        private EntityList _ValueList = new EntityList();

        /// <summary>
        /// Множество значений с которым будет сравниваться множество значений экземпляра 
        /// </summary>
        public EntityList ValueList { get { return _ValueList; } set { _ValueList = value; } }

        /// <summary>
        /// Заполняет PropertyList из строки в качестве разделителя - зпт
        /// </summary>
        /// <param name="FindStr"></param>
        public virtual void SetPropertyList(string FindStr)
        {
            ValueList.Clear();
            FindStr = FindStr.Replace(" ", "");
            string[] s = FindStr.Split(",".ToCharArray()[0]);
            foreach (string item in s)
            {
                if (item.Length < 3) continue;
                ValueList.Add(new EntitySingle { ID = "%" + item + "%" });
            }
        }

        /// <summary>
        /// Строит строчку из FropertyList, обратка SetPropertyList
        /// </summary>
        /// <returns></returns>
        public virtual string GetFropertyList()
        {
            StringBuilder result = new StringBuilder();
            foreach (EntitySingle item in ValueList)
            {
                if (item.ID.Length < 3) continue;
                result.Append(item.ID.Replace("%", ""));
                result.Append(",");

            }
            return result.ToString();

        }


        [EntityNonSerialized]
        public int StartRowIndex { get { return _StartRowIndex; } set { _StartRowIndex = value; } }

        [EntityNonSerialized]
        public int EndRowIndex { get { return _EndRowIndex; } set { _EndRowIndex = value; } }

        public override string ImAsXML
        {
            get
            {
                StringBuilder sb;
                MemoryStream ms = new MemoryStream();
                sb = new StringBuilder();
                StringWriter sw = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
                XmlTextWriter w = new XmlTextWriter(sw);
                w.Formatting = Formatting.Indented;
                w.Indentation = 3;

                w.WriteStartElement(tgWhereCondition);
                ValueList.Reset();
                foreach (EntitySingle item in ValueList)
                {
                    w.WriteStartElement(tgParamValueItem);
                    w.WriteAttributeString(attID, item.ID);
                    w.WriteEndElement();
                }


                w.WriteStartElement(tgPageSize);
                w.WriteAttributeString(attStartRowIndex, StartRowIndex.ToString());
                w.WriteAttributeString(attEndRowIndex, (EndRowIndex).ToString());
                w.WriteEndElement();

                w.WriteEndElement();

                return sb.ToString();

            }
        }

    }

    
   
    
}
